package net.ib.mtalk.network.pipeline;

import net.ib.mtalk.util.MTalkLogWriter;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.replay.ReplayingDecoder;

import android.os.PowerManager;

/**
 * Stream -> ChannelBuffer<br>
 * 프레임 길이 정보를 처리하는 레이어.<br>
 * <br>
 * 한 프레임의 형태는 다음과 같다.<br>
 * [Big Endian 4 byte Integer: size of Envelpe][serialized Envelpe]<br>
 * <br>
 * cf. <a href=http://docs.jboss.org/netty/3.2/api/org/jboss/netty/handler/codec/replay/ReplayingDecoder.html>web API://org.jboss.netty.handler.codec.replay.ReplayingDecoder</a>
 * @author Arngard
 *
 */
public class StreamBufferDecoder extends ReplayingDecoder<StreamBufferDecoder.MyDecoderState> {

	private int length = 0;
	private PowerManager.WakeLock mWakeLock; 

	/**
	 * 명시적으로 초기 상태를 정의하여 객체 생성
	 */
	public StreamBufferDecoder(PowerManager.WakeLock wakeLock) {
		super(MyDecoderState.READ_LENGTH);	// state init
		mWakeLock = wakeLock;
	}

	@Override
	protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, MyDecoderState state) throws Exception {
		MTalkLogWriter.v(this.getClass().getSimpleName()+".decode() - STT");

		if(mWakeLock != null) mWakeLock.acquire();
		
		try {
			switch (state) {
			case READ_LENGTH:
				length = buffer.readInt();
				checkpoint(MyDecoderState.READ_CONTENT);
			case READ_CONTENT:
				ChannelBuffer frame = buffer.readBytes(length);
				checkpoint(MyDecoderState.READ_LENGTH);
				
				return frame;
			default:
				throw new Error("Should not reach here.");
			}
		} finally {
			if(mWakeLock != null) mWakeLock.release();
			
			MTalkLogWriter.v(this.getClass().getSimpleName()+".decode() - END");
		}
	}
	
	/**
	 * {@link StreamBufferDecoder}에서 디코드 페이즈를 관리하기 위해 사용한다.
	 * @author Arngard
	 */
	enum MyDecoderState {
		READ_LENGTH,
		READ_CONTENT;
	};

}


